#define DEBUG
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;

namespace ICSharpCode.TextEditor.Document
{
    public class SelectionManager : IDisposable
    {
        private bool mutilSelect = false;

        private int selectionMaxLine = 0;

        private int selectionMaxCloumn = 0;

        private TextArea textArea;

        private IDocument document;

        private TextLocation selectionStart;

        private TextLocation selectionEnd;

       // private TextLocation selectionMax;

        internal int DrawLineX1pos = 0;

        internal int DrawLineX2pos = 0;

        internal int DrawLineY1pos = 0;

        internal int DrawLineY2pos = 0;

        internal SelectFrom selectFrom = new SelectFrom();

        internal List<ISelection> selectionCollection = new List<ISelection>();

        internal TextLocation SelectionStart
        {
            get
            {
                return selectionStart;
            }
            set
            {
                DefaultDocument.ValidatePosition(document, value);
                selectionStart = value;
            }
        }

        internal TextLocation SelectionEnd
        {
            get
            {
                return selectionEnd;
            }
            set
            {
                selectionEnd = value;
            }
        }

        internal TextLocation SelectionMax => new TextLocation(selectionMaxCloumn, selectionMaxLine);

        public List<ISelection> SelectionCollection => selectionCollection;

        public bool HasSomethingSelected => selectionCollection.Count > 0;

        public bool HasSomethingMutilLinesSeleted
        {
            get
            {
                if (mutilSelect && selectionCollection.Count > 0)
                {
                    return selectionEnd.Column > selectionStart.Column;
                }
                return false;
            }
        }

        public bool IsMutilSelect
        {
            get
            {
                return mutilSelect;
            }
            internal set
            {
                mutilSelect = value;
            }
        }

        public bool SelectionIsReadonly
        {
            get
            {
                if (document.ReadOnly)
                {
                    return true;
                }
                foreach (ISelection item in selectionCollection)
                {
                    if (SelectionIsReadOnly(document, item))
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public string SelectedText
        {
            get
            {
                StringBuilder stringBuilder = new StringBuilder();
                if (mutilSelect)
                {
                    foreach (ISelection item in selectionCollection)
                    {
                        stringBuilder.Append(item.SelectedText);
                    }
                }
                else
                {
                    foreach (ISelection item2 in selectionCollection)
                    {
                        if (item2.IsCurrent)
                        {
                            stringBuilder.Append(item2.SelectedText);
                        }
                    }
                }
                return stringBuilder.ToString();
            }
        }

        public event EventHandler SelectionChanged;

        internal static bool SelectionIsReadOnly(IDocument document, ISelection sel)
        {
            if (document.TextEditorProperties.SupportReadOnlySegments)
            {
                return document.MarkerStrategy.GetMarkers(sel.Offset, sel.Length).Exists((TextMarker m) => m.IsReadOnly);
            }
            return false;
        }

        public SelectionManager(IDocument document)
        {
            this.document = document;
            document.DocumentChanged += DocumentChanged;
        }

        public SelectionManager(IDocument document, TextArea textArea)
        {
            this.document = document;
            this.textArea = textArea;
            document.DocumentChanged += DocumentChanged;
        }

        public void Dispose()
        {
            if (document != null)
            {
                document.DocumentChanged -= DocumentChanged;
                document = null;
            }
        }

        private void DocumentChanged(object sender, DocumentEventArgs e)
        {
            if (e.Text == null)
            {
                Remove(e.Offset, e.Length);
            }
            else if (e.Length < 0)
            {
                Insert(e.Offset, e.Text);
            }
            else
            {
                Replace(e.Offset, e.Length, e.Text);
            }
        }

        public void SetSelection(ISelection selection)
        {
            if (selection != null)
            {
                selection.SetSelectIsCurrent(iscurrent: true);
                if (SelectionCollection.Count != 1 || !(selection.StartPosition == SelectionCollection[0].StartPosition) || !(selection.EndPosition == SelectionCollection[0].EndPosition))
                {
                    ClearWithoutUpdate();
                    selectionCollection.Add(selection);
                    document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, selection.StartPosition.Y, selection.EndPosition.Y));
                    document.CommitUpdate();
                    OnSelectionChanged(EventArgs.Empty);
                }
            }
            else
            {
                ClearSelection();
            }
        }

        public void SetSelection(TextLocation startPosition, TextLocation endPosition)
        {
            SetSelection(new DefaultSelection(document, startPosition, endPosition));
        }

        public bool GreaterEqPos(TextLocation p1, TextLocation p2)
        {
            return p1.Y > p2.Y || (p1.Y == p2.Y && p1.X >= p2.X);
        }

        public void ExtendSelection(TextLocation oldPosition, TextLocation newPosition)
        {
            if (oldPosition == newPosition)
            {
                return;
            }
            int x = newPosition.X;
            TextLocation textLocation;
            TextLocation textLocation2;
            if (GreaterEqPos(oldPosition, newPosition))
            {
                textLocation = newPosition;
                textLocation2 = oldPosition;
            }
            else
            {
                textLocation = oldPosition;
                textLocation2 = newPosition;
            }
            if (textLocation == textLocation2)
            {
                return;
            }
            if (!HasSomethingSelected)
            {
                SetSelection(new DefaultSelection(document, textLocation, textLocation2));
                if (selectFrom.where == 0)
                {
                    SelectionStart = oldPosition;
                }
                return;
            }
            ISelection selection = selectionCollection[0];
            if (textLocation == textLocation2)
            {
                return;
            }
            if (selectFrom.where == 1)
            {
                newPosition.X = 0;
            }
            if (GreaterEqPos(newPosition, SelectionStart))
            {
                selection.StartPosition = SelectionStart;
                if (selectFrom.where == 1)
                {
                    selection.EndPosition = new TextLocation(textArea.Caret.Column, textArea.Caret.Line);
                }
                else
                {
                    newPosition.X = x;
                    selection.EndPosition = newPosition;
                }
            }
            else
            {
                if (selectFrom.where == 1 && selectFrom.first == 1)
                {
                    selection.EndPosition = NextValidPosition(SelectionStart.Y);
                }
                else
                {
                    selection.EndPosition = SelectionStart;
                }
                selection.StartPosition = newPosition;
            }
            selectionEnd = textLocation2;
            document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, textLocation.Y, textLocation2.Y));
            document.CommitUpdate();
            OnSelectionChanged(EventArgs.Empty);
        }

        public void ExtendALTSelection()
        {
            int line = selectionStart.Line;
            int line2 = selectionEnd.Line;
            selectionCollection.Clear();
            for (int i = line; i <= line2; i = checked(i + 1))
            {
                if (selectionEnd.Column >= selectionStart.Column)
                {
                    NewLineSelection item = new NewLineSelection(document, new TextLocation(selectionStart.Column, i), new TextLocation(selectionEnd.Column, i));
                    selectionCollection.Add(item);
                }
            }
            document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, line, line2));
            document.CommitUpdate();
            OnSelectionChanged(EventArgs.Empty);
        }

        public void PaintSelectionRange(Graphics g)
        {
            checked
            {
                if (IsMutilSelect && selectionCollection.Count > 0)
                {
                    DrawLineX1pos = textArea.TextView.DrawingPosition.X + textArea.TextView.GetDrawingXPos(SelectionStart.Line, SelectionStart.Column);
                    DrawLineX2pos = textArea.TextView.DrawingPosition.X + textArea.TextView.GetDrawingXPos(SelectionEnd.Line, SelectionEnd.Column);
                    DrawLineY1pos = textArea.TextView.DrawingPosition.Y + textArea.Document.GetVisibleLine(SelectionStart.Line) * textArea.TextView.FontHeight - textArea.TextView.TextArea.VirtualTop.Y;
                    DrawLineY2pos = textArea.Caret.ScreenPosition.Y + textArea.TextView.FontHeight - 1;
                    HighlightColor colorFor = textArea.Document.HighlightingStrategy.GetColorFor("Selection");
                    g.DrawLine(new Pen(colorFor.BackgroundColor, 1f), new Point(DrawLineX1pos, DrawLineY1pos), new Point(DrawLineX1pos, DrawLineY2pos));
                    g.FillRectangle(new SolidBrush(colorFor.BackgroundColor), DrawLineX1pos, DrawLineY1pos, DrawLineX2pos - DrawLineX1pos + 1, DrawLineY2pos - DrawLineY1pos);
                }
            }
        }

        public void PaintSelectionRange(Graphics g, int lineNum, RectangleF lineRectangle)
        {
            checked
            {
                if (IsMutilSelect && selectionCollection.Count > 0 && selectionCollection.Exists((ISelection w) => w.StartPosition.Line == lineNum))
                {
                    float num = textArea.TextView.DrawingPosition.X + textArea.TextView.GetDrawingXPos(SelectionStart.Line, SelectionStart.Column);
                    float num2 = textArea.TextView.DrawingPosition.X + textArea.TextView.GetDrawingXPos(SelectionEnd.Line, SelectionEnd.Column);
                    float top = lineRectangle.Top;
                    float num3 = lineRectangle.Top + lineRectangle.Height;
                    HighlightColor colorFor = textArea.Document.HighlightingStrategy.GetColorFor("Selection");
                    g.DrawLine(new Pen(colorFor.BackgroundColor, 1f), new PointF(num, top), new PointF(num, num3));
                    g.FillRectangle(new SolidBrush(colorFor.BackgroundColor), num, top, num2 - num + 1f, num3 - top);
                }
            }
        }

        public TextLocation NextValidPosition(int line)
        {
            checked
            {
                if (line < document.TotalNumberOfLines - 1)
                {
                    return new TextLocation(0, line + 1);
                }
                return new TextLocation(document.GetLineSegment(document.TotalNumberOfLines - 1).Length + 1, line);
            }
        }

        internal void ClearWithoutUpdate()
        {
            checked
            {
                while (selectionCollection.Count > 0)
                {
                    ISelection selection = selectionCollection[selectionCollection.Count - 1];
                    selectionCollection.RemoveAt(selectionCollection.Count - 1);
                    document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, selection.StartPosition.Y, selection.EndPosition.Y));
                    OnSelectionChanged(EventArgs.Empty);
                }
                if (IsMutilSelect)
                {
                    document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, selectionStart.Y, selectionEnd.Y));
                }
                DrawLineX1pos = 0;
                DrawLineX2pos = 0;
                DrawLineY1pos = 0;
                DrawLineY2pos = 0;
                selectionMaxCloumn = 0;
                selectionMaxLine = 0;
                if (IsMutilSelect)
                {
                    selectionStart = default(TextLocation);
                    SelectionEnd = default(TextLocation);
                }
            }
        }

        public void ClearSelection()
        {
            Point mousepos = textArea.mousepos;
            selectFrom.first = selectFrom.where;
            checked
            {
                TextLocation logicalPosition = textArea.TextView.GetLogicalPosition(mousepos.X - textArea.TextView.DrawingPosition.X, mousepos.Y - textArea.TextView.DrawingPosition.Y);
                if (selectFrom.where == 1)
                {
                    logicalPosition.X = 0;
                }
                if (logicalPosition.Line >= document.TotalNumberOfLines)
                {
                    logicalPosition.Line = document.TotalNumberOfLines - 1;
                    logicalPosition.Column = document.GetLineSegment(document.TotalNumberOfLines - 1).Length;
                }
                SelectionStart = logicalPosition;
                ClearWithoutUpdate();
                document.CommitUpdate();
            }
        }

        public void ClearMutilSelect()
        {
            int line = selectionStart.Line;
            int line2 = selectionEnd.Line;
            selectionStart = textArea.Caret.Position;
            SelectionEnd = textArea.Caret.Position;
            document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, line, line2));
            document.CommitUpdate();
        }

        public void RemoveSelectedText()
        {
            if (SelectionIsReadonly)
            {
                ClearSelection();
                return;
            }
            List<int> list = new List<int>();
            int num = -1;
            bool flag = true;
            foreach (ISelection item in selectionCollection)
            {
                if (item.IsCurrent)
                {
                    if (flag)
                    {
                        int y = item.StartPosition.Y;
                        if (y != item.EndPosition.Y)
                        {
                            flag = false;
                        }
                        else
                        {
                            list.Add(y);
                        }
                    }
                    num = item.Offset;
                    document.Remove(item.Offset, item.Length);
                }
                if (IsMutilSelect)
                {
                    item.EndPosition = new TextLocation(item.StartPosition.Column, item.StartPosition.Line);
                }
            }
            if (!IsMutilSelect)
            {
                ClearSelection();
            }
            else if (num >= 0)
            {
                selectionEnd = new TextLocation(document.OffsetToPosition(num).Column, selectionEnd.Line);
            }
            if (num >= 0)
            {
                textArea.Caret.Position = document.OffsetToPosition(num);
            }
            if (num == -1)
            {
                return;
            }
            if (flag)
            {
                foreach (int item2 in list)
                {
                    document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, item2));
                }
            }
            else
            {
                document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
            }
            document.CommitUpdate();
        }

        private bool SelectionsOverlap(ISelection s1, ISelection s2)
        {
            return checked((s1.Offset <= s2.Offset && s2.Offset <= s1.Offset + s1.Length) || (s1.Offset <= s2.Offset + s2.Length && s2.Offset + s2.Length <= s1.Offset + s1.Length) || (s1.Offset >= s2.Offset && s1.Offset + s1.Length <= s2.Offset + s2.Length));
        }

        public bool IsSelected(int offset)
        {
            return GetSelectionAt(offset) != null;
        }

        public ISelection GetSelectionAt(int offset)
        {
            foreach (ISelection item in selectionCollection)
            {
                if (item.ContainsOffset(offset))
                {
                    return item;
                }
            }
            return null;
        }

        internal void Insert(int offset, string text)
        {
        }

        internal void Remove(int offset, int length)
        {
        }

        internal void Replace(int offset, int length, string text)
        {
        }

        public List<ColumnRange> GetSelectionsAtLine(int lineNumber)
        {
            List<ColumnRange> list = new List<ColumnRange>();
            foreach (ISelection item in selectionCollection)
            {
                int y = item.StartPosition.Y;
                int y2 = item.EndPosition.Y;
                if (y < lineNumber && lineNumber < y2)
                {
                    list.Add(ColumnRange.WholeColumn);
                    break;
                }
                if (y == lineNumber && y2 == lineNumber)
                {
                    LineSegment lineSegment = document.GetLineSegment(y);
                    int x = item.StartPosition.X;
                    int x2 = item.EndPosition.X;
                    list.Add(new ColumnRange(x, x2, item.IsCurrent));
                    continue;
                }
                if (y == lineNumber)
                {
                    LineSegment lineSegment2 = document.GetLineSegment(y);
                    int x3 = item.StartPosition.X;
                    int endColumn = checked(lineSegment2.Length + 1);
                    list.Add(new ColumnRange(x3, endColumn, item.IsCurrent));
                    break;
                }
                if (y2 == lineNumber)
                {
                    int x4 = item.EndPosition.X;
                    list.Add(new ColumnRange(0, x4, item.IsCurrent));
                    break;
                }
            }
            return list;
        }

        public ColumnRange GetSelectionAtLine(int lineNumber)
        {
            foreach (ISelection item in selectionCollection)
            {
                int y = item.StartPosition.Y;
                int y2 = item.EndPosition.Y;
                if (y < lineNumber && lineNumber < y2)
                {
                    return ColumnRange.WholeColumn;
                }
                if (y == lineNumber)
                {
                    LineSegment lineSegment = document.GetLineSegment(y);
                    int x = item.StartPosition.X;
                    int endColumn = ((y2 == lineNumber) ? item.EndPosition.X : checked(lineSegment.Length + 1));
                    return new ColumnRange(x, endColumn, item.IsCurrent);
                }
                if (y2 == lineNumber)
                {
                    int x2 = item.EndPosition.X;
                    return new ColumnRange(0, x2, item.IsCurrent);
                }
            }
            return ColumnRange.NoColumn;
        }

        public void FireSelectionChanged()
        {
            OnSelectionChanged(EventArgs.Empty);
        }

        protected virtual void OnSelectionChanged(EventArgs e)
        {
            if (SelectionChanged != null)
            {
                SelectionChanged(this, e);
            }
        }
    }
}
